﻿using System;

namespace TheLocal.Common
{
    public sealed class LazyLoad<T> where T : class
    {
        private readonly Func<T> valueFactory;
        private readonly Action<T> valueInitializer;
        private readonly object instanceSyncObject = new object();
        private volatile T instance;

        public LazyLoad()
        {
        }

        public LazyLoad(Func<T> valueFactory)
        {
            this.valueFactory = valueFactory;
        }

        public LazyLoad(Action<T> valueInitializer)
        {
            this.valueInitializer = valueInitializer;
        }

        public LazyLoad(Func<T> valueFactory, Action<T> valueInitializer)
        {
            this.valueFactory = valueFactory;
            this.valueInitializer = valueInitializer;
        }

        public bool HasValue
        {
            get
            {
                lock (this.instanceSyncObject)
                {
                    return this.instance != null;
                }
            }
        }

        public T Value
        {
            get
            {
                if (this.instance == null)
                {
                    lock (this.instanceSyncObject)
                    {
                        if (this.instance == null)
                        {
                            this.instance = this.valueFactory != null ? this.valueFactory() : Activator.CreateInstance<T>();

                            if (this.valueInitializer != null)
                            {
                                this.valueInitializer(this.instance);
                            }
                        }
                    }
                }
                return this.instance;
            }
        }
    }
}
